/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.rocketmq.client.common;

import java.util.Random;

/**
 *
 */
public class ThreadLocalIndex {

    /**
     * 使用ThreadLocal记录索引值，确保线程安全
     */
    private final ThreadLocal<Integer> threadLocalIndex = new ThreadLocal<>();

    /**
     * 随机值
     */
    private final Random random = new Random();

    /**
     * 使用该值为与随机值，确保生成的随机值为正，作为消息队列索引的值。
     */
    private final static int POSITIVE_MASK = 0x7FFFFFFF;

    /**
     * 获取当前线程的索引值，在该索引值的基础上加1
     * @return
     */
    public int incrementAndGet() {
        // 获取当前线程对应的索引值
        Integer index = this.threadLocalIndex.get();
        // 如果没有索引值，则随机生成一个新的索引值
        if (null == index) {
            index = random.nextInt();
        }
        // 将当前线程对应的索引值加1，保存到ThreadLocal中，或者更新ThreadLocal中的现有索引值
        this.threadLocalIndex.set(++index);
        // 使用位与操作确保索引值为正值。
        return index & POSITIVE_MASK;
    }

    /**
     * 1. 生成随机值，使用绝对值操作确保值非负。
     * 2. 设置线程本地的索引值。
     */
    public void reset() {
        int index = Math.abs(random.nextInt(Integer.MAX_VALUE));
        if (index < 0) {
            index = 0;
        }
        // 设置线程本地的索引值。
        this.threadLocalIndex.set(index);
    }

    @Override
    public String toString() {
        return "ThreadLocalIndex{" +
            "threadLocalIndex=" + threadLocalIndex.get() +
            '}';
    }
}
